use num_bigint::BigUint;
use thiserror::Error;

use crate::{BlockHeight, OpCode, Script};

pub mod interpreter;
pub(crate) mod p2pkh;

pub use p2pkh::{
    create_tx_input_script, create_tx_output_script_0, get_block_height, get_transaction_receiver,
    get_transaction_sender,
};

#[derive(Error, Debug, PartialEq)]
pub enum ScriptError {
    #[error("Invalid opcode")]
    InvalidOpcode,
    #[error("Invalid public key")]
    InvalidPublicKey,
    #[error("Invalid signature")]
    InvalidSignature,
    #[error("Stack underflow")]
    StackUnderflow,
    #[error("Verification failed")]
    VerificationFailed,
    #[error("Script invalid length")]
    ScriptInvalidLength,

    #[error("Equalverify false")]
    EqualverifyFalse,

    #[error("Invalid script")]
    InvalidScript,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Operand {
    Bool(bool),
    Data(Vec<u8>),
}

// CTransaction txNew;
// txNew.vin[0].prevout.SetNull();
// txNew.vin[0].scriptSig << nBits << ++bnExtraNonce;
pub fn create_tx_input_script_for_coinbase(nbits: u32, block_height: BlockHeight) -> Script {
    let mut script: Script = Script::new_empty();
    script.push(OpCode::OpData(nbits.to_le_bytes().to_vec()));
    script.push(OpCode::OpBlockHeight(block_height));
    script
}

// txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4)
pub fn create_tx_input_script_for_coinbase_of_genesis_block() -> Script {
    let data = "Mini-Chain project for learning Blockchain starts from 2025-01-01!";
    Script::new(vec![
        OpCode::OpData(486604799u32.to_le_bytes().to_vec()), // bitcoin magic number
        OpCode::OpBlockHeight(0),
        OpCode::OpData(data.as_bytes().to_vec()),
    ])
}

pub fn create_tx_input_script_for_coinbase_of_mining(
    nbits: u32,
    block_height: BlockHeight,
    extra_nonce: &BigUint,
) -> Script {
    Script::new(vec![
        OpCode::OpData(nbits.to_le_bytes().to_vec()), // bitcoin magic number
        OpCode::OpBlockHeight(block_height),
        OpCode::OpData(extra_nonce.to_bytes_be().to_vec()),
    ])
}
